#pragma once
#include "noncopyable.h"

#include <vector>
#include <string>
#include <algorithm>

/// +-------------------+------------------+------------------+
/// | prependable bytes |  readable bytes  |  writable bytes  |
/// |                   |     (CONTENT)    |                  |
/// +-------------------+------------------+------------------+
/// |                   |                  |                  |
/// 0      <=      readerIndex   <=   writerIndex    <=     size

class Buffer : noncopyable
{
public:
    static const size_t KChecpPrepend = 8;  // 缓存区prependable的初始大小
    static const size_t KInitiaSize = 1024; // writeable的初始大小，readable的大小初始是0

    explicit Buffer(size_t initialSize = KInitiaSize)
        : buffer_(KChecpPrepend + initialSize),
          readerIndex_(KChecpPrepend),
          writerIndex_(KChecpPrepend)
    {
    }

    void swap(Buffer& rhs)
    {
        buffer_.swap(rhs.buffer_);
        std::swap(readerIndex_,rhs.readerIndex_);
        std::swap(writerIndex_,rhs.writerIndex_);
    }

    size_t readableBytes() const 
    {
        return writerIndex_ - readerIndex_;
    }

    size_t writeableBytes() const
    {
        return buffer_.size() - writerIndex_;
    }

    size_t prependableBytes() const
    {
        return readerIndex_;
    }

    const char *peek() const
    {
        return begin() + readerIndex_;
    }

    void retrieve(size_t len) 
    {
        if (len < readableBytes())
        {
            // 数据充足的时候，只取走len的大小
            readerIndex_ += len;
        }
        else  // len == readableBytes()
        {
            // 如果数据不足，取走所有的数据
            retrieveAll();
        }
    }

    void retrieveAll()
    {
        readerIndex_ = writerIndex_ = KChecpPrepend;
    }


    std::string retrieveAllAsString()
    {
        return retrieveAsString(readableBytes());
    }

    std::string retrieveAsString(size_t len)
    {
        std::string result(peek(),len);
        retrieve(len);
        return result;
    }

    // buffer_.size() - writerIndex_
    void ensureWriteableBytes(size_t len)
    {
        if (writeableBytes() < len)
        {
            makeSpace(len);
        } 
    }
    
    void makeSpace(size_t len)
    {
        // 如果可写的大小 + 前面已经读了的（空闲出来的大小） 如果还不够要求的len  那么就扩容
        if(writeableBytes() + prependableBytes() < len + KChecpPrepend)
        {
            buffer_.resize(writerIndex_ + len);
        }
        else    // 说明前面已经空闲出来的大小和可写的大小够len   那么就将readerIndex_ 移动到KCheckpPreend
        {
            size_t readable = readableBytes();
            std::copy(begin() + readerIndex_,
                      begin() + writerIndex_,
                      begin() + KChecpPrepend);
            readerIndex_ = KChecpPrepend;
            writerIndex_ = readerIndex_ + readable;
        }
    }

    // 将[data,data + len] 添加到buffer缓存区中
    void append(const char* data,size_t len)
    {
        ensureWriteableBytes(len);
        std::copy(data,data+len,beginWrite());
        writerIndex_ += len;
    }

    char* beginWrite()
    {
        return begin() + writerIndex_;
    }

    // 通过fd读取数据
    ssize_t readFd(int fd,int* saveErrno);
    // 通过fd发送数据
    ssize_t writeFd(int fd,int* saveErrno);
private:
    char* begin()
    {
        return &*buffer_.begin();
    }

    const char* begin() const
    {
        return &*buffer_.begin();
    }

    std::vector<char> buffer_;
    size_t readerIndex_;
    size_t writerIndex_;
};